package com.cjx.stars.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cjx.stars.common.MyException;
import com.cjx.stars.common.Response;
import com.cjx.stars.common.ResponseUtils;
import com.cjx.stars.mapper.ChatMapper;
import com.cjx.stars.pojo.request.ChatRequest;
import com.cjx.stars.pojo.table.Chat;
import com.cjx.stars.pojo.table.Team;
import com.cjx.stars.pojo.table.User;
import com.cjx.stars.pojo.vo.ChatMessageVO;
import com.cjx.stars.pojo.vo.UserVo;
import com.cjx.stars.pojo.vo.WebSocketVO;
import com.cjx.stars.service.ChatService;
import com.cjx.stars.service.TeamService;
import com.cjx.stars.service.UserService;
import com.cjx.stars.utils.UserHolder;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.cjx.stars.constant.ChatConstant.*;
import static com.cjx.stars.constant.FailMessage.PARAMETER_ABNORMAL;
import static com.cjx.stars.constant.RedisConstant.*;

/**
 * @author cjx
 * @description 针对表【chat(聊天消息表)】的数据库操作Service实现
 * @createDate 2024-04-13 19:32:14
 */
@Service
public class ChatServiceImpl extends ServiceImpl<ChatMapper, Chat>
        implements ChatService {

    @Resource
    private UserService userService;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private TeamService teamService;

    @Override
    public ChatMessageVO chatResult(Long userId, Long toId, String text, Integer chatType, DateTime createTime) {
        //1.构造消息返回包装类
        ChatMessageVO chatMessageVo = new ChatMessageVO();
        //1.1查找来源用户，目标用户
        User fromUser = userService.getById(userId);
        User toUser = userService.getById(toId);
        //1.2将用户类转换成聊天用户数据类
        WebSocketVO fromWebSocketVo = new WebSocketVO();
        WebSocketVO toWebSocketVo = new WebSocketVO();
        BeanUtils.copyProperties(fromUser, fromWebSocketVo);
        BeanUtils.copyProperties(toUser, toWebSocketVo);
        //1.3将消息包装类设置其属性
        chatMessageVo.setFromUser(fromWebSocketVo);
        chatMessageVo.setToUser(toWebSocketVo);
        chatMessageVo.setChatType(chatType);
        chatMessageVo.setText(text);
        chatMessageVo.setCreateTime(DateUtil.format(createTime, "yyyy-MM-dd HH:mm:ss"));
        //2.返回数据
        return chatMessageVo;
    }

    /**
     * 聊天结果
     *
     * @param userId 用户id
     * @param text   文本
     * @return {@link ChatMessageVO}
     */
    private ChatMessageVO chatResult(Long userId, String text) {
        //1.构造消息返回包装类
        ChatMessageVO chatMessageVo = new ChatMessageVO();
        //1.1查找来源用户
        User fromUser = userService.getById(userId);
        //1.2将用户类转换成聊天用户数据类
        WebSocketVO fromWebSocketVo = new WebSocketVO();
        BeanUtils.copyProperties(fromUser, fromWebSocketVo);
        //1.3将消息包装类设置其属性
        chatMessageVo.setFromUser(fromWebSocketVo);
        chatMessageVo.setText(text);
        return chatMessageVo;
    }

    /**
     * 删除密钥
     *
     * @param key 缓存key
     * @param id  id
     */
    @Override
    public void deleteKey(String key, String id) {
        if (key.equals(CACHE_CHAT_HALL)) {
            redisTemplate.delete(key);
        } else {
            redisTemplate.delete(key + id);
        }
    }

    @Override
    public Response<?> getPrivateChat(ChatRequest chatRequest, int chatType) {
        UserVo loginUser = UserHolder.getUser();
        //1.检查参数
        Long toId = chatRequest.getToId();
        if (toId == null) {
            throw new MyException(PARAMETER_ABNORMAL);
        }
        //2.尝试从缓存中获取聊天数据
        List<ChatMessageVO> chatRecords = getCache(CACHE_CHAT_PRIVATE, loginUser.getUserId() + toId);
        if (chatRecords != null) {
            //2.1刷新缓存时间
            saveCache(CACHE_CHAT_PRIVATE, loginUser.getUserId() + toId, chatRecords);
            return ResponseUtils.success(chatRecords);
        }
        //3.构造条件去查询相关聊天记录
        LambdaQueryWrapper<Chat> chatLambdaQueryWrapper = new LambdaQueryWrapper<>();
        //3.1条件包含当前用户发送给目标用户的信息 或者 反之 ， 信息类型要和当前的聊天形式保持一致
        chatLambdaQueryWrapper
                .and(privateChat -> privateChat.eq(Chat::getFromId, loginUser.getUserId()).eq(Chat::getToId, toId)
                        .or().
                        eq(Chat::getToId, loginUser.getUserId()).eq(Chat::getFromId, toId)
                ).eq(Chat::getChatType, chatType);
        // 两方共有聊天
        List<Chat> list = this.list(chatLambdaQueryWrapper);
        //3.2将每条原始聊天信息包装成返回聊天信息
        List<ChatMessageVO> chatMessageVOList = list.stream().map(chat -> {
            ChatMessageVO chatMessageVo = chatResult(Long.valueOf(loginUser.getUserId()),
                    toId, chat.getText(), chatType,
                    DateTime.of(chat.getCreateTime()));
            //3.3判断此条信息的发送人是否为登录用户
            if (chat.getFromId().equals(Long.valueOf(loginUser.getUserId()))) {
                chatMessageVo.setIsMy(true);
            }
            return chatMessageVo;
        }).collect(Collectors.toList());
        //4.将查询的聊天信息存入缓存
        saveCache(CACHE_CHAT_PRIVATE, loginUser.getUserId() + toId, chatMessageVOList);
        return ResponseUtils.success(chatMessageVOList);
    }

    /**
     * 获取缓存
     *
     * @param redisKey redis键
     * @param id       id
     * @return {@link List}<{@link ChatMessageVO}>
     */
    @Override
    public List<ChatMessageVO> getCache(String redisKey, String id) {
        ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
        List<ChatMessageVO> chatRecords;
        if (redisKey.equals(CACHE_CHAT_HALL)) {
            chatRecords = (List<ChatMessageVO>) valueOperations.get(redisKey);
        } else {
            chatRecords = (List<ChatMessageVO>) valueOperations.get(redisKey + id);
        }
        return chatRecords;
    }

    /**
     * 保存缓存
     *
     * @param redisKey       redis键
     * @param id             id
     * @param chatMessageVos 聊天消息列表
     */
    @Override
    public void saveCache(String redisKey, String id, List<ChatMessageVO> chatMessageVos) {
        try {
            ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
            // 解决缓存雪崩
            int i = RandomUtil.randomInt(MINIMUM_CACHE_RANDOM_TIME, MAXIMUM_CACHE_RANDOM_TIME);
            if (redisKey.equals(CACHE_CHAT_HALL)) {
                valueOperations.set(
                        redisKey,
                        chatMessageVos,
                        MINIMUM_CACHE_RANDOM_TIME + i / CACHE_TIME_OFFSET,
                        TimeUnit.MINUTES);
            } else {
                valueOperations.set(
                        redisKey + id,
                        chatMessageVos,
                        MINIMUM_CACHE_RANDOM_TIME + i / CACHE_TIME_OFFSET,
                        TimeUnit.MINUTES);
            }
        } catch (Exception e) {
            log.error("redis set key error");
        }
    }

    @Override
    public Response<?> getTeamChat(ChatRequest chatRequest, int chatType) {
        Long teamId = chatRequest.getTeamId();
        UserVo loginUser = UserHolder.getUser();
        //1.检查参数
        if (teamId == null) {
            throw new MyException(PARAMETER_ABNORMAL);
        }
        //2.查询缓存中是否有此队伍聊天记录信息
        List<ChatMessageVO> chatRecords = getCache(CACHE_CHAT_TEAM, String.valueOf(teamId));
        if (chatRecords != null) {
            List<ChatMessageVO> chatMessageVos = checkIsMyMessage(loginUser, chatRecords);
            saveCache(CACHE_CHAT_TEAM, String.valueOf(teamId), chatMessageVos);
            return ResponseUtils.success(chatMessageVos);
        }
        //3.查询队伍数据
        Team team = teamService.getById(teamId);
        LambdaQueryWrapper<Chat> chatLambdaQueryWrapper = new LambdaQueryWrapper<>();
        chatLambdaQueryWrapper.eq(Chat::getChatType, chatType).eq(Chat::getTeamId, teamId);
        //4.查询并封装队伍聊天记录
        List<ChatMessageVO> chatMessageVos = returnMessage(loginUser, team.getUserId(), chatLambdaQueryWrapper);
        //5.保存队伍聊天记录到缓存中
        saveCache(CACHE_CHAT_TEAM, String.valueOf(teamId), chatMessageVos);
        return ResponseUtils.success(chatMessageVos);
    }

    @Override
    public Response<?> getHallChat(int chatType) {
        UserVo loginUser = UserHolder.getUser();
        //1.缓存中查询
        List<ChatMessageVO> chatRecords = getCache(CACHE_CHAT_HALL, String.valueOf(loginUser.getUserId()));
        if (chatRecords != null) {
            List<ChatMessageVO> chatMessageVos = checkIsMyMessage(loginUser, chatRecords);
            saveCache(CACHE_CHAT_HALL, String.valueOf(loginUser.getUserId()), chatMessageVos);
            return ResponseUtils.success(chatMessageVos);
        }
        //2.数据库查询
        LambdaQueryWrapper<Chat> chatLambdaQueryWrapper = new LambdaQueryWrapper<>();
        chatLambdaQueryWrapper.eq(Chat::getChatType, chatType);
        List<ChatMessageVO> chatMessageVos = returnMessage(loginUser, null, chatLambdaQueryWrapper);
        //3.保存信息到缓存中
        saveCache(CACHE_CHAT_HALL, String.valueOf(loginUser.getUserId()), chatMessageVos);
        return ResponseUtils.success(chatMessageVos);
    }

    /**
     * 返回消息
     *
     * @param loginUser              登录用户
     * @param userId                 用户id
     * @param chatLambdaQueryWrapper 聊天lambda查询包装器
     * @return 队伍聊天记录
     */
    private List<ChatMessageVO> returnMessage(UserVo loginUser,
                                              Long userId,
                                              LambdaQueryWrapper<Chat> chatLambdaQueryWrapper) {
        //1.查询聊天记录
        List<Chat> chatList = this.list(chatLambdaQueryWrapper);
        return chatList.stream().map(chat -> {
            //2.封装聊天记录返回类
            ChatMessageVO chatMessageVo = chatResult(chat.getFromId(), chat.getText());
            if (chat.getFromId().equals(Long.valueOf(loginUser.getUserId()))) {
                chatMessageVo.setIsMy(true);
            }
            chatMessageVo.setCreateTime(DateUtil.format(chat.getCreateTime(), "yyyy年MM月dd日 HH:mm:ss"));
            return chatMessageVo;
        }).collect(Collectors.toList());
    }

    /**
     * 检查每条信息记录是否是我发送的
     *
     * @param loginUser   登录用户
     * @param chatRecords 聊天记录
     * @return 检查后的信息记录
     */
    private List<ChatMessageVO> checkIsMyMessage(UserVo loginUser, List<ChatMessageVO> chatRecords) {
        return chatRecords.stream().peek(chat -> {
            if (!chat.getFromUser().getUserId().equals(Long.valueOf(loginUser.getUserId())) && chat.getIsMy()) {
                chat.setIsMy(false);
            }
            if (chat.getFromUser().getUserId().equals(Long.valueOf(loginUser.getUserId())) && !chat.getIsMy()) {
                chat.setIsMy(true);
            }
        }).collect(Collectors.toList());
    }
}




